package coreSimulation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Observable;
import java.util.Observer;

import queue.Queue;
import dropOffDesk.DropOffDesk;

public class LoadBalancer implements Observer {
	private DropOffDesk[] desks;
	private Queue queue;
	private static final int MAX_QUEUE_SIZE = 6;
	private static final int MIN_QUEUE_SIZE = 2;

	/**
	 * The LoadBalancer manages the opening and closing of drop-off desk in
	 * response to changes in the size of the queue. The update method
	 */
	public LoadBalancer(DropOffDesk[] desks, Queue queue) {
		this.desks = desks;
		this.queue = queue;
		queue.addObserver(this);

	}

	/**
	 * Update method of observer pattern. When the queue changes this method is
	 * called to open or closes desks as necessary
	 */
	@Override
	public void update(Observable arg0, Object arg1) {

		// record all the desks that are currently open so we can randomly
		// choose one if we need to close a desk
		ArrayList<Integer> openDesks = new ArrayList<Integer>();

		// record all the desks that are currently closed so we can randomly
		// choose one if we need to open a desk
		ArrayList<Integer> closedDesks = new ArrayList<Integer>();

		// find out which desks are currently open and closed
		for (int i = 0; i < desks.length; i++) {
			if (desks[i].getIsOpen()) {
				openDesks.add(i);
			} else {
				closedDesks.add(i);
			}

		}

		// if the queue size is bigger than the allowed maximum for the number
		// of desks currently available and the program hasn't
		// been closed (i.e. they can still board the flight,
		// we're not just logging remaining passengers),
		// open another random desk if there is one available
		if (queue.getSize() > MAX_QUEUE_SIZE * openDesks.size() && closedDesks
				.size() > 0 && queue.getIsOpen()) {
			// randomize the list ArrayList of desks
			Collections.shuffle(closedDesks);
			DropOffDesk desk = desks[closedDesks.get(0)];
			synchronized (desk) {
				if (!desk.getIsOpen()) {
					// open desk and start processing queue
					desk.setIsOpen(true);
					Thread t = new Thread(desk);
					t.start();
				}
			}

		}

		// if the queue size is currently smaller than the minimum queue size
		// allowed for the number of desks currently open, close a random desk
		// but always leave one open
		else if (queue.getSize() < MIN_QUEUE_SIZE * openDesks.size() && openDesks
				.size() > 1 && openDesks.size() > 1) {
			// randomize the list ArrayList of desks
			Collections.shuffle(openDesks);
			DropOffDesk desk = desks[openDesks.get(0)];
			synchronized (desk) {
				if (desk.getIsOpen()) {
					// close desk
					desk.setIsOpen(false);
				}
			}

		}
	}

}
